import java.util.Vector;

public class Population implements Comparable<Population>
{
	private Vector<Nucleotide> population;

	// Copie l'ensemble de depart.
	public Population(Population dp)
	{
		this.population = new Vector<Nucleotide>(16);
		for (int i = 0; i < dp.size(); i++)
		{
			this.add(new Nucleotide(dp.get(i)));
		}
	}

	public Population()
	{
		this.population = new Vector<Nucleotide>(16);
	}

	public void PopulationBase()
	{
		char tab[] = { 'A', 'C', 'G', 'T' };
		for (int i = 0; i < 16; i++)
		{
			population.add(new Nucleotide(tab[i / 4], tab[i % 4]));
		}
	}

	public void PopulationBase(String letter)
	{
		population = new Vector<Nucleotide>(16);
		for (int i = 0; i < 16; i++)
		{
			population.add(new Nucleotide(letter.charAt(i / 4), letter
					.charAt(i % 4)));
		}
	}

	public boolean add(Nucleotide d)
	{
		return population.add(d);
	}

	public void clear()
	{
		population.clear();
	}

	public Nucleotide remove(int index)
	{
		return this.population.remove(index);
	}

	public Nucleotide get(int index)
	{
		return population.get(index);
	}

	public int size()
	{
		return population.size();
	}

	public boolean isEmpty()
	{
		return size() == 0;
	}

	public Nucleotide set(int index, Nucleotide d)
	{
		return this.population.set(index, d);
	}

	public boolean hasMemberOf(Nucleotide d)
	{
		for (int i = 0; i < size(); i++)
		{
			if (get(i).isGreaterThan(d) == 0)
				return true;
		}
		return false;
	}

	public Population complementarity()
	{
		Population dp = new Population(this);
		for (int i = 0; i < dp.size(); i++)
		{
			dp.set(i, dp.get(i).complementarity());
		}
		return dp;
	}

	public String toString()
	{
		StringBuffer res = new StringBuffer();
		for (int i = 0; i < size(); i++)
		{
			res.append(get(i).getFirst()).append(get(i).getSecond());
			if (i != (size() - 1))
				res.append(" ");
		}
		return new String(res);
	}

	public boolean isSelfComplementary()
	{
		// diPopulation comp = complementarity();
		/*
		 * complementarity().display(); display(); boolean res =
		 * isGreaterThan(complementarity()) == 0; System.out.println("  "+ res);
		 */
		return isGreaterThan(complementarity()) == 0;
	}

	public int isGreaterThan(Population dp)
	{
		// On trie notre ensemble
		this.quickSort();
		dp.quickSort();
		int nbPop;
		if (dp.size() < this.size())
			nbPop = dp.size();
		else
			nbPop = this.size();
		int test;
		for (int i = 0; i < nbPop; i++)
		{
			test = this.get(i).isGreaterThan(dp.get(i));
			if (test != 0)
				return test;
		}
		if (dp.size() < this.size())
			return 1;
		else if (dp.size() > this.size())
			return -1;
		else
			return 0;
	}

	public int compareTo(Population o)
	{
		return isGreaterThan(o);
	}

	public boolean isIncludeIn(Population dp)
	{
		if (this.size() > dp.size())
			return false;
		this.quickSort();
		dp.quickSort();
		int j = 0;
		int i = 0;
		for (i = 0; i < size() && j < dp.size(); i++, j++)
		{
			if (get(i).isGreaterThan(dp.get(j)) < 0)
				return false;
			if (get(i).isGreaterThan(dp.get(j)) > 0)
			{
				if (j + 1 == dp.size())
					return false;
				i--;
			}
		}
		return i == size();
	}

	// Tri l'ensemble de l'objet.
	public void quickSort()
	{
		quickSortAux(0, population.size() - 1);
	}

	private void quickSortAux(int inf, int sup)
	{
		if (inf > sup)
			return;

		int borne_sup = sup;
		int borne_inf = inf;
		short test;
		while (borne_inf < borne_sup)
		{
			test = this.get(borne_inf).isGreaterThan(this.get(borne_inf + 1));
			if (test > 0)
			{
				population.set(borne_inf, population.set(borne_inf + 1,
						population.get(borne_inf)));
				borne_inf++;
			}
			else if (test < 0)
			{
				population.set(borne_sup, population.set(borne_inf + 1,
						population.get(borne_sup)));
				borne_sup--;
			}
			else
			{
				System.out
						.println("\nClass diPopulation : Deux elements sont identiques ! (ne devrait pas arriver)");
				System.exit(-1);
			}
		}
		quickSortAux(inf, borne_inf - 1);
		quickSortAux(borne_inf + 1, sup);
	}

	public boolean isCircularCode2()
	{
		for (int i = 0; i < size(); i++)
		{
			if (!isCircularCode2Aux(get(i), 1))
				return false;
		}
		return true;

	}

	public boolean isCircularCode2Aux(Nucleotide n, int count)
	{
		if (count == 5)
			return false;
		for (int i = 0; i < size(); i++)
		{
			if (n.getSecond() == get(i).getFirst())
			{
				if (!isCircularCode2Aux(get(i), count + 1))
					return false;
			}
		}
		return true;
	}

	public boolean isCircularCode()
	{
		if (size() == 0)
			return false;
		boolean res = true;
		for (int i = 0; i < size(); i++)
			res &= isCircularCodeAux(null, i);
		return res;
	}

	public boolean isCircularCodeAux(Population dinuc_study, int indice_study)
	{
		if (dinuc_study == null)
		{
			dinuc_study = new Population();
			dinuc_study.add(population.get(indice_study));
		}
		for (int i = 0; i < size(); i++)
		{
			if (dinuc_study.get(dinuc_study.size() - 1).getSecond() == population
					.get(i).getFirst())
			{
				if (population.get(i).getSecond() == dinuc_study.get(0)
						.getFirst())
					return false;
				else
				{
					if (dinuc_study.hasMemberOf(population.get(i)))
					{ // dinuc_study.display();
						return false;
					}
					dinuc_study.add(population.get(i));
					if (!isCircularCodeAux(dinuc_study, i))
					{// dinuc_study.display(); System.out.println();
						return false;
					}
					dinuc_study.remove(dinuc_study.size() - 1);
				}
			}
		}
		return true;
	}

	public void display()
	{
		for (int i = 0; i < population.size(); i++)
		{
			System.out.print(' ');
			population.get(i).display();
		}
	}
}
